#pragma  once
#include "feDefs.h"

template <class T>
class fePolyline
{
public:
	struct V2
	{
		T X;
		T Y;

		friend V2 operator - (V2 &iV1, V2 &iV2) { V2 res; res.X = iV1.X - iV2.X; res.Y = iV1.Y - iV2.Y; return res;}
	};


private:
	V2		*Points;
	int		NumPoints;
	int		NumAllocated;

public:
	fePolyline()					{ NumPoints = 0; Points = 0; }
	fePolyline(V2 *iPoints, int iN)	{ Init(iPoints, iN); }


	//-----------------------------------------------------------------------------------------------------------------------------------------
	void Filter(int iMedianWidth=5)
	{return;
		//abs
		for(int i=0; i<NumPoints; i++)
		{
			if(Points[i].Y < 0) Points[i].Y *= -1;
		}
		

		//median
		double median_points[100] = {};
// 		double oldpoints[100] = {};
// 		for(int i=0; i<iMedianWidth/2+1; i++)
// 			oldpoints[i] = Points[i].Y;

		for(int i=iMedianWidth/2 + 1; i<NumPoints - iMedianWidth/2 - 1; i++)
		{
			for(int m=0; m<iMedianWidth; m++)
			{
				median_points[m] = Points[i-iMedianWidth/2].Y;
			}						

			//sort median
			for(int k=0; k<iMedianWidth; k++)
			{
				double t = median_points[k];
				int j = k;
				for (int j = k; j > 0 && median_points[j-1] > t; j--)
					median_points[j] = median_points[j-1];
				median_points[j] = t;
			}
			Points[i].Y = median_points[iMedianWidth/2+1];
		}
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	void LoadFromFile(char *iFileName)
	{
		Points = new V2[1000];
		NumAllocated = 1000;
		NumPoints = 0;


		//try open file
		FILE *file = fopen(iFileName, "r");
		if(!file) return;
		double t = 0;
		double f = 0;

		//skip first 2 lines
		char buf[1024];
		fscanf(file, "%[^\n]", buf);
		fgetc(file);
		fscanf(file, "%[^\n]", buf);
		fgetc(file);
		while(!feof(file)) 
		{
			//scan line
			if(fscanf(file, "%lf %lf", &t, &f))
			{
				Points[NumPoints].X = t;
				Points[NumPoints].Y = f;
				NumPoints++;
			}
			else
			{
				break;
				//skip line
				//fscanf(file, "%[^\n]", buf);
				//fgetc(file);
			}
		}
		fclose(file);
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	void Init(V2 *iPoints, int iN)
	{
		if(iN <= 0) return;

		NumPoints = iN;
		Points = new V2[NumPoints];
		NumAllocated = NumPoints;
		if(iPoints)
			memcpy(Points, iPoints, iN*sizeof(V2));		
		else
			ZeroMemory(Points, NumPoints*sizeof(V2));
	}

	
	//-----------------------------------------------------------------------------------------------------------------------------------------
	void CopyFrom(fePolyline<T> &iPoly)
	{
		Allocate(iPoly.GetSize());
		memcpy(Points, iPoly.Points, iPoly.GetSize()*sizeof(V2));
		NumPoints = iPoly.GetSize();
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	void Allocate(int iN)
	{
		if(iN <= 0) return;
		if(iN == NumAllocated) return;

		NumPoints = 0;
		NumAllocated = iN;
		Points = new V2[iN];
	}
	

	//-----------------------------------------------------------------------------------------------------------------------------------------
	void Clear() { NumPoints = 0; }
	

	//-----------------------------------------------------------------------------------------------------------------------------------------
	void Free()
	{ 
		NumPoints = 0; 
		if(Points) 
			delete [] Points; 
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	bool Push(T iX, T iY)
	{
		//check
		if(NumPoints >= NumAllocated)
			return false;


		//add point to the end
		V2 p;
		p.X = iX;
		p.Y = iY;
		Points[NumPoints++] = p;


		//done
		return true;
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	V2  GetPoint(int iIndex){ return Points[iIndex]; }
	int GetSize()			{ return NumPoints; }
	V2* ToArray()			{ return Points; }
	V2  operator []	(int iIndex) const	 { return Points[iIndex]; }
	V2& operator []	(int iIndex) { return Points[iIndex]; }
	
	
	//-----------------------------------------------------------------------------------------------------------------------------------------
	T  GetF(T iX) 
	{	
		int ind = 0;
		//find point
		for(ind=0; ind<NumPoints; ind++)
		{
			if(Points[ind].X < iX) break;
		}


		//get f over linear interpolation
		double xs[2] = { (double)Points[ind-1].X, (double)Points[ind].X};
		double fs[2] = { (double)Points[ind-1].Y, (double)Points[ind].Y};
		return feInterpolation::Linear(xs, fs, iX);
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	bool TestPoint(V2 *iP)
	{
		//test intersection of x=c with each side
		//assume P[n+1] = P[0];
		int numinter = 0;
		for(int i=0; i<NumPoints-1; i++)
		{
			double x1 = Points[i].X;
			double y1 = Points[i].Y;
			double x2 = Points[i+1].X;
			double y2 = Points[i+1].Y;

			if(x1 == x2)
			{
				if(x1 == iP->X) numinter++;
				continue;
			}

			double t = (iP->X - x1)/(x2 - x1);
			double y = y1 + (y2-y1)*t;

			if(y >= iP->Y && t >= 0 && t <= 1)
				numinter++;
		}

		//check last side
		double x1 = Points[NumPoints-1].X;
		double y1 = Points[NumPoints-1].Y;
		double x2 = Points[0].X;
		double y2 = Points[0].Y;

		if(x1 == x2)
		{
			if(x1 == iP->X) numinter++;
		}
		else 
		{
			double t = (iP->X - x1)/(x2 - x1);
			double y = y1 + (y2-y1)*t;
			if(y >= iP->Y && t >= 0 && t <= 1)
				numinter++;
		}


		//if numinter %2 == 0 - not in polygon
		return numinter%2 != 0;
	}


	//-----------------------------------------------------------------------------------------------------------------------------------------
	double MeanSquareDeviation(fePolyline<T> iOther, int iNumPointsToCheck)
	{
		double s = 0;
		for(int i=0; i<iNumPointsToCheck; i++)
		{
			s += (Points[i].Y - iOther.Points[i].Y)*(Points[i].Y - iOther.Points[i].Y)/iOther.Points[i].Y/iOther.Points[i].Y
		}
		return s;
	}
};